use std::cmp::Ordering;

struct ArrayList<T> {
    data: Vec<T>,
}

impl<T> ArrayList<T> {
    fn new() -> Self {
        ArrayList { data: Vec::new() }
    }

    fn append(&mut self, item: T) {
        self.data.push(item);
    }

    fn prepend(&mut self, item: T) {
        self.data.insert(0, item);
    }

    fn insert(&mut self, index: usize, item: T) -> Result<(), String> {
        if index > self.data.len() {
            Err(String::from("Index out of bounds"))
        } else {
            self.data.insert(index, item);
            Ok(())
        }
    }

    fn remove(&mut self, index: usize) -> Result<T, String> {
        if index >= self.data.len() {
            Err(String::from("Index out of bounds"))
        } else {
            Ok(self.data.remove(index))
        }
    }

    fn remove_range(&mut self, start: usize, end: usize) -> Result<(), String> {
        if start > end || end > self.data.len() {
            Err(String::from("Invalid range"))
        } else {
            self.data.drain(start..end);
            Ok(())
        }
    }

    fn index_of<F>(&self, predicate: F) -> Option<usize>
    where
        F: Fn(&T) -> bool,
    {
        self.data.iter().position(predicate)
    }

    fn clear(&mut self) {
        self.data.clear();
    }

    fn sort_by<F>(&mut self, compare: F)
    where
        F: FnMut(&T, &T) -> Ordering,
    {
        self.data.sort_by(compare);
    }
}

fn main() {
    let mut list = ArrayList::new();

    // Test append
    list.append(1);
    assert_eq!(list.data, vec![1]);

    // Test prepend
    list.prepend(0);
    assert_eq!(list.data, vec![0, 1]);

    // Test insert
    list.insert(1, 2).unwrap();
    assert_eq!(list.data, vec![0, 2, 1]);

    // Test remove
    let removed = list.remove(1).unwrap();
    assert_eq!(removed, 2);
    assert_eq!(list.data, vec![0, 1]);

    // Test remove_range
    list.append(3);
    list.append(4);
    list.remove_range(1, 3).unwrap();
    assert_eq!(list.data, vec![0, 4]);

    // Test index_of
    let index = list.index_of(|&x| x == 4).unwrap();
    assert_eq!(index, 1);

    // Test clear
    list.clear();
    assert_eq!(list.data.len(), 0);

    // Test sort_by
    list.append(3);
    list.append(1);
    list.append(2);
    list.sort_by(|a, b| a.cmp(b));
    assert_eq!(list.data, vec![1, 2, 3]);
}
